/*************************************************************
 *Name:           Christopher Alexander
 *Email address:  alexanc2@onid.oregonstate.edu
 *Class name:     CS362-400
 *Assignment:     Team 9 - Project Test getWinners()
 *Description:    The program will peform unit testing on the
 *                dominion.c function getWinners().
 *************************************************************/

#include "dominion.h"
#include "dominion_helpers.h"
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "rngs.h"

/*Function Prototypes*/
int preScoreFor (int, struct gameState *preState);
void checkGetWinners(struct gameState *testState);


/*This function is used to generate a value for score that
 *should be identical to the value calculated by scoreFor()
 *Params: p - the player to check the score of.
 *        preState - a pointer to a struct gameState that contains.
                     a score to be calculated.
 *Return: the score of player p.
 */
int preScoreFor (int p, struct gameState *preState) {

   int i;
   int score = 0;

   //score from hand
   for (i = 0; i < preState->handCount[p]; i++){
      if (preState->hand[p][i] == curse) { score = score - 1; };
      if (preState->hand[p][i] == estate) { score = score + 1; };
      if (preState->hand[p][i] == duchy) { score = score + 3; };
      if (preState->hand[p][i] == province) { score = score + 6; };
      if (preState->hand[p][i] == great_hall) { score = score + 1; };
      if (preState->hand[p][i] == gardens) { score = score + ( fullDeckCount(p, 0, preState) / 10 ); };
   }

   //score from discard
   for (i = 0; i < preState->discardCount[p]; i++){
      if (preState->discard[p][i] == curse) { score = score - 1; };
      if (preState->discard[p][i] == estate) { score = score + 1; };
      if (preState->discard[p][i] == duchy) { score = score + 3; };
      if (preState->discard[p][i] == province) { score = score + 6; };
      if (preState->discard[p][i] == great_hall) { score = score + 1; };
      if (preState->discard[p][i] == gardens) { score = score + ( fullDeckCount(p, 0, preState) / 10 ); };
   }

   //score from deck
   for (i = 0; i < preState->deckCount[p]; i++){
      if (preState->deck[p][i] == curse) { score = score - 1; };
      if (preState->deck[p][i] == estate) { score = score + 1; };
      if (preState->deck[p][i] == duchy) { score = score + 3; };
      if (preState->deck[p][i] == province) { score = score + 6; };
      if (preState->deck[p][i] == great_hall) { score = score + 1; };
      if (preState->deck[p][i] == gardens) { score = score + ( fullDeckCount(p, 0, preState) / 10 ); };
   }
   return score;
}


/*This function will calculate the winners in two ways,
 *and then compare the results to make sure they are the same.
 *1)The getwinners() function of dominion.c will be used.
 *2)The winners will be determined manually.
 *Params: state - a pointer to a struct gameState that contains.
 *Return: None.
 */
void checkGetWinners(struct gameState *state) {
   int i;
   int highScore = -9999;
   int playersTest[MAX_PLAYERS];
   int playersCheck[MAX_PLAYERS];

   //Get a result using getWinners()
   getWinners(playersTest, state);

   //Get a result manually

   //Calculate score.
   for (i = 0; i < state->numPlayers; i++){
      playersCheck[i] = preScoreFor(i, state);
   }
   //Determine highest score
   for (i = 0; i < state->numPlayers; i++){
      if (playersCheck[i] > highScore){
         highScore = playersCheck[i];
      }
   }
   //If a player has the highscore and has had fewer turns, add one to their score.
   for (i = 0; i < state->numPlayers; i++){
      if (playersCheck[i] == highScore && i > state->whoseTurn){
         playersCheck[i]++;
      }
   }
   //Determine the highest score again.
   for (i = 0; i < state->numPlayers; i++){
      if (playersCheck[i] > highScore){
         highScore = playersCheck[i];
      }
   }

   //Find the winner(s)
   for (i = 0; i < state->numPlayers; i++){
      if (playersCheck[i] == highScore){
         playersCheck[i] = 1;
      }
      else {
         playersCheck[i] = 0;
      }
   }

   //End get a result manually.

   //Check that results of two methods are the same.
   for (i = 0; i < state->numPlayers; i++){
      assert(playersTest[i] == playersCheck[i]);
   }

}


int main() {
   int i, j, n, p;
   struct gameState G;

   /*These are the cards that scoreFor checks. This array will be used to
   randomly assign a card to G.deck, G.discard, and G.hand */
   int scoreCards[6] = {curse, estate, duchy, province, great_hall, gardens};
   int randomCard;

   printf("\nTesting getWinners():\n");

   for (n = 0; n < 2000; n++) {

      //Fill gameState with random garbage.
      for (i = 0; i < sizeof(struct gameState); i++){
         ((char*)&G)[i] = (int) (Random() * 256);
      }

      //Randomly set the number of players to be 2, 3, or 4.
      p = (int) (Random() * 3) + 2;
      G.numPlayers = p;

      //Randomly set size of deck, discard, and hand for each player.
      //Range of 0-9 is used to increase the chance of tie games.
      for (i = 0; i < p; i++){
         G.deckCount[i] = (int) (Random() * 10);
         G.discardCount[i] = (int) (Random() * 10);
         G.handCount[i] = (int) (Random() * 10);
      }

      //For each player, randomly fill their decks with scoring cards.
      for (i = 0; i < p; i++){
         for (j = 0; j < G.deckCount[i]; j++){
            randomCard = (int) (Random() * 6);
            G.deck[i][j] = scoreCards[randomCard];
         }

         for (j = 0; j < G.discardCount[i]; j++){
            randomCard = (int) (Random() * 6);
            G.discard[i][j] = scoreCards[randomCard];
         }

         for (j = 0; j < G.handCount[i]; j++){
            randomCard = (int) (Random() * 6);
            G.hand[i][j] = scoreCards[randomCard];
         }
      }

      //Set whoseTurn to be a random player.
      G.whoseTurn = (int) (Random() * G.numPlayers);

      checkGetWinners(&G);
   }
   printf("All tests of getWinners() passed!\n");
   return 0;
}
